             package com.java.diagnostics.visualizer.recommender;
             
             import com.java.diagnostics.visualizer.data.AggregateData;
             import com.java.diagnostics.visualizer.data.DataPoint;
             import com.java.diagnostics.visualizer.data.StructuredData;
             import com.java.diagnostics.visualizer.data.StructuredDataBuilder;
             import com.java.diagnostics.visualizer.data.TupleData;
             import com.java.diagnostics.visualizer.data.UnstructuredData;
             import com.java.diagnostics.visualizer.data.UnstructuredDataBuilder;
             import com.java.diagnostics.visualizer.factory.DataFactory;
             import com.java.diagnostics.visualizer.gc.recommender.RecommendationPreferenceHelper;
             import com.java.diagnostics.visualizer.gc.solarissupport.parser.OracleVGCLabels;
             import com.java.diagnostics.visualizer.impl.factory.LogFactory;
             import com.java.diagnostics.visualizer.parser.javadump.InstanceJavaDumpParser;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCAxes;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCGCScopes;
             import com.java.diagnostics.visualizer.parser.vgc.sovereign.InstanceSovereignVGCParser;
             import com.java.diagnostics.visualizer.recommender.util.Messages;
             import com.java.diagnostics.visualizer.recommender.util.RecommendationLabels;
             import java.util.Map;
             import java.util.logging.Logger;
             import java.util.regex.Matcher;
             import java.util.regex.Pattern;
             
             public class RecommendationBase
             {
               private static final String IBM = "IBM";
               protected static final int ONE_HUNDRED_PERCENT = 100;
               protected RecommendationPreferenceHelper helper;
               protected static final int UNSET = -1;
               protected static final DataFactory vgcFactory = DataFactory.getFactory("VGC");
               
               protected static final DataFactory hiddenFactory = DataFactory.getFactory(DataFactory.HIDDEN);
               
               protected static final DataFactory nativeFactory = DataFactory.getFactory("Native memory");
               protected static final String GENCON = "gencon";
               protected static final String BALANCED = "balanced";
               protected static final String OPTTHRUPUT = "optthruput";
               protected static final String OPTAVGPAUSE = "optavgpause";
               protected static final String G1MODE = "G1";
               protected static final String NURSERY_SIZE = "-Xmn";
               protected static final String XGCPOLICY_GENCON = "-Xgcpolicy:gencon";
               protected static final String XGCPOLICY = "-Xgcpolicy:";
               protected static final String XMINF = "-Xminf";
               protected static final String MX = "-mx";
               protected static final int MAX_32_BIT_HEAP_SIZE = 1500;
               protected static final String SUN_VERSION = OracleVGCLabels.VERSION;
               
               protected static final String METRONOME = "metronome";
               private static final String[] sixtyFourArch = { "ppc64", "amd64", "s390x" };
               
               private static final Pattern J9REGEX = Pattern.compile("20[0-9][0-9][0-9][0-9][0-9][0-9]_[A-Z][A-Z]");
               
               private static final Logger TRACE = LogFactory.getTrace(RecommendationBase.class);
               
               public RecommendationBase() {
                 this.helper = new RecommendationPreferenceHelper();
               }
               
               public void addToActionSummary(AggregateData data, String key, Object value) {
                 StructuredData actionSummary = data
                   .getStructuredData("action.summary");
                 if (actionSummary == null) {
                   actionSummary = vgcFactory.createStructuredData(
                     "action.summary", 
                     Messages.getString("action.summary"));
                   data.add(actionSummary);
                 }
                 ((StructuredDataBuilder)actionSummary).put(key, value);
               }
               
               public void addToActionCounts(AggregateData data, String key, int value) {
                 StructuredData actionCounts = data
                   .getStructuredData("action.counts");
                 if (actionCounts == null) {
                   actionCounts = vgcFactory.createStructuredData(
                     "action.counts", 
                     Messages.getString("action.counts"));
                   data.add(actionCounts);
                 }
                 ((StructuredDataBuilder)actionCounts).put(key, Integer.valueOf(value));
               }
               
               public void addToSummary(AggregateData data, String key, Object value) {
                 StructuredData summary = data.getStructuredData("summary");
                 if (summary == null) {
                   summary = vgcFactory.createStructuredData("summary", 
                     Messages.getString("summary"));
                   data.add(summary);
                 }
                 ((StructuredDataBuilder)summary).put(key, value);
               }
               
               public void addToQuantumSummary(AggregateData data, String key, Object value)
               {
                 StructuredData summary = data
                   .getStructuredData("quantum.pause.summary");
                 if (summary == null) {
                   summary = vgcFactory.createStructuredData("quantum.pause.summary", 
                     RecommendationLabels.QUANTUM_PAUSE_SUMMARY);
                   data.add(summary);
                 }
                 ((StructuredDataBuilder)summary).put(key, value);
               }
               
               public void addComment(AggregateData data, String comment) {
                 UnstructuredData tuning = data
                   .getUnstructuredData("tuning.recommendation");
                 if (tuning == null) {
                   tuning = createUnstructuredData("tuning.recommendation");
                   data.add(tuning);
                 }
                 ((UnstructuredDataBuilder)tuning).addComment(comment);
               }
               
               private void addCommentOnce(AggregateData data, String comment) {
                 UnstructuredData tuning = data
                   .getUnstructuredData("tuning.recommendation");
                 if (tuning == null) {
                   tuning = createUnstructuredData("tuning.recommendation");
                   data.add(tuning);
                 }
                 boolean hasComment = false;
                 String[] comments = ((UnstructuredDataBuilder)tuning).getComments();
                 
                 for (String line : comments) {
                   if (line.equalsIgnoreCase(comment)) {
                     hasComment = true;
                   }
                 }
                 if (!hasComment) {
                   ((UnstructuredDataBuilder)tuning).addComment(comment);
                 }
               }
               
               public void addWarning(AggregateData data, String warning) {
                 UnstructuredData tuning = data
                   .getUnstructuredData("tuning.recommendation");
                 if (tuning == null) {
                   tuning = createUnstructuredData("tuning.recommendation");
                   data.add(tuning);
                 }
                 ((UnstructuredDataBuilder)tuning).addWarning(warning);
               }
               
               public void addProblem(AggregateData data, String problem) {
                 UnstructuredData tuning = data
                   .getUnstructuredData("tuning.recommendation");
                 if (tuning == null) {
                   tuning = createUnstructuredData("tuning.recommendation");
                   data.add(tuning);
                 }
                 ((UnstructuredDataBuilder)tuning).addProblem(problem);
               }
               
               public void addGoodThing(AggregateData data, String goodThing) {
                 UnstructuredData tuning = data
                   .getUnstructuredData("tuning.recommendation");
                 if (tuning == null) {
                   tuning = createUnstructuredData("tuning.recommendation");
                   data.add(tuning);
                 }
                 ((UnstructuredDataBuilder)tuning).addGoodThing(goodThing);
               }
               
               public void addToCommandLine(AggregateData data, String key, Object value) {
                 StructuredData commandLine = data.getStructuredData("command.line");
                 if (commandLine == null) {
                   commandLine = hiddenFactory.createStructuredData("command.line", 
                     Messages.getString("command.line"));
                   data.add(commandLine);
                 }
                 ((StructuredDataBuilder)commandLine).put(key, value);
               }
               
               public Object getGCMode(AggregateData data) {
                 StructuredData summary = data.getStructuredData("summary");
                 if (summary == null) {
                   return "UNKNOWN";
                 }
                 return summary.getContents().get(RecommendationLabels.GC_MODE);
               }
               
               public int getGlobalPauses(AggregateData data)
               {
                 StructuredData summary = data.getStructuredData("summary");
                 if (summary == null) {
                   return -1;
                 }
                 String gcMode = (String)getGCMode(data);
                 String label = null;
                 if ("gencon".equalsIgnoreCase(gcMode)) {
                   label = makeLabel(RecommendationLabels.GLOBAL_COLLECTIONS, 
                     RecommendationLabels.NUMBER_OF_COLLECTIONS);
                 } else if (("optavgpause".equalsIgnoreCase(gcMode)) || 
                   ("optthruput".equalsIgnoreCase(gcMode))) {
                   label = RecommendationLabels.NUMBER_OF_COLLECTIONS;
                 }
                 Object pauses = summary.getContents().get(label);
                 if (pauses != null) {
                   return ((Integer)pauses).intValue();
                 }
                 return -1;
               }
               
               private UnstructuredData createUnstructuredData(String label)
               {
                 return vgcFactory.createUnstructuredData(label, 
                   Messages.getString(label));
               }
               
               private UnstructuredData createNativeUnstructuredData(String label) {
                 return nativeFactory.createUnstructuredData(label, 
                   Messages.getString(label));
               }
               
               public Object getOverhead(AggregateData data) {
                 StructuredData summary = data.getStructuredData("summary");
                 if (summary == null) {
                   return Integer.valueOf(-1);
                 }
                 return 
                 
                   summary.getContents().get(
                   RecommendationLabels.PROPORTION_OF_TIME_SPENT_IN_GARBAGE_COLLECTION_PAUSES);
               }
               
               public void addProblemToNativeAnalysis(AggregateData data, String comment)
               {
                 UnstructuredData tuning = data
                   .getUnstructuredData("native.tuning.recommendation");
                 if (tuning == null) {
                   tuning = createNativeUnstructuredData("native.tuning.recommendation");
                   data.add(tuning);
                 }
                 ((UnstructuredDataBuilder)tuning).addProblem(comment);
               }
               
               public void addWarningToNativeAnalysis(AggregateData data, String comment) {
                 UnstructuredData tuning = data
                   .getUnstructuredData("native.tuning.recommendation");
                 if (tuning == null) {
                   tuning = createNativeUnstructuredData("native.tuning.recommendation");
                   data.add(tuning);
                 }
                 ((UnstructuredDataBuilder)tuning).addWarning(comment);
               }
               
               public void addGoodThingToNativeAnalysis(AggregateData data, String comment) {
                 UnstructuredData tuning = data
                   .getUnstructuredData("native.tuning.recommendation");
                 if (tuning == null) {
                   tuning = createNativeUnstructuredData("native.tuning.recommendation");
                   data.add(tuning);
                 }
                 ((UnstructuredDataBuilder)tuning).addGoodThing(comment);
               }
               
               protected double getMeanAsUnits(TupleData tuple, String unitname) {
                 double convertedY = tuple.getMeanY(unitname);
                 return convertedY;
               }
               
               protected double getMeanAsMB(TupleData tuple) {
                 return getMeanAsUnits(tuple, VGCAxes.MB);
               }
               
               protected double getMaxAsMB(TupleData tuple) {
                 return tuple.getMaxY(VGCAxes.MB);
               }
               
               protected int getMeanAsPercent(TupleData tuple)
               {
                 double mean = tuple.getMeanY(VGCAxes.PERCENT_SIGN);
                 return (int)Math.round(mean);
               }
               
               protected boolean genconAvailable(AggregateData data) {
                 boolean genconAvailable = false;
                 UnstructuredData version = data.getUnstructuredData("VGCLabels.version");
                 if (version != null) {
                   String versionData = version.getValue().trim();
                   Matcher matcher = J9REGEX.matcher(versionData);
                   if (matcher.find()) {
                     genconAvailable = true;
                   }
                 }
                 return genconAvailable;
               }
               
               protected boolean isSovereign(AggregateData data)
               {
                 UnstructuredData version = data.getUnstructuredData("VGCLabels.version");
                 if (version != null) {
                   return InstanceSovereignVGCParser.VERSION.equals(
                     version.getValue().trim());
                 }
                 return false;
               }
               
               protected boolean isSun(AggregateData data)
               {
                 UnstructuredData version = data.getUnstructuredData("VGCLabels.version");
                 if (version != null) {
                   return SUN_VERSION.equals(version.getValue().trim());
                 }
                 return false;
               }
               
               protected boolean isConcurrent(AggregateData data)
               {
                 StructuredData summary = data.getStructuredData("summary");
                 String gcMode = (String)summary.getContents().get(
                   RecommendationLabels.GC_MODE);
                 if (gcMode != null) {
                   if (gcMode.equals("optavgpause")) {
                     return true;
                   }
                   if (gcMode.equals("gencon")) {
                     return true;
                   }
                   
                 }
                 else if ((isIBM(data)) && (!isJavacore(data)))
                 {
                   TRACE.warning("RecommendationBase.isConcurrent called before " + 
                     RecommendationLabels.GC_MODE + 
                     " determined. Recommendations may be running out of order.");
                 }
                 
                 return false;
               }
               
               protected boolean isGenerational(AggregateData data) {
                 StructuredData summary = data.getStructuredData("summary");
                 if (summary != null) {
                   String gcMode = (String)summary.getContents().get(
                     RecommendationLabels.GC_MODE);
                   if (gcMode != null) {
                     if (gcMode.equals("gencon")) {
                       return true;
                     }
                     
                   }
                   else if ((isIBM(data)) && (!isJavacore(data)))
                   {
                     TRACE.warning("RecommendationBase.isGenerational called before " + 
                       RecommendationLabels.GC_MODE + 
                       " determined. Recommendations may be running out of order.");
                   }
                 }
                 
                 return false;
               }
               
               protected boolean isIBM(AggregateData data) {
                 UnstructuredData version = data.getUnstructuredData("VGCLabels.version");
                 boolean isIBM = (version != null) && 
                   (version.getValue().contains("IBM"));
                 return isIBM;
               }
               
               protected boolean is26VM(AggregateData data)
               {
                 TupleData afSuccess = data.getTupleData("VGCLabels.af.success");
                 
                 return afSuccess != null;
               }
               
               protected boolean isJavacore(AggregateData data) {
                 StructuredData fileType = data
                   .getStructuredData(InstanceJavaDumpParser.class.getName());
                 
                 if (fileType == null) {
                   return false;
                 }
                 boolean isJavacore = fileType.getContents().get(
                   "FILETYPE").equals("javacore");
                 return isJavacore;
               }
               
               protected String makeLabel(String label, String content)
               {
                 if (label == null) {
                   return content;
                 }
                 return label + " - " + content;
               }
               
               protected boolean isCollectionOfGivenScope(TupleData scopeRecord, DataPoint point, int identifier)
               {
                 boolean is = identifier == VGCGCScopes.GLOBAL_INT;
                 
                 if (scopeRecord != null) {
                   DataPoint reason = scopeRecord.getDataPoint(point.getSequenceUID());
                   if (reason != null) {
                     is = reason.getRawY() == identifier;
                   }
                 }
                 return is;
               }
               
               protected void suggestHeapSizes(AggregateData data) {
                 TupleData occupancy = data
                   .getTupleData("VGCLabels.live.normal.heap.after.gc");
                 
                 if (occupancy != null) {
                   double meanOccupancyInMB = getMeanAsMB(occupancy);
                   
                   double maxOccupancyInMB = getMaxAsMB(occupancy);
                   
                   int suggestedHeap = (int)Math.round(Math.max(
                     meanOccupancyInMB / 0.3D, maxOccupancyInMB / 0.7D));
                   
                   if (!is64bitSystem(data)) {
                     suggestedHeap = Math.min(1500, suggestedHeap);
                   }
                   addToCommandLine(data, "-mx", "-mx" + suggestedHeap + "m");
                 }
                 String gcMode = (String)getGCMode(data);
                 
                 if ("gencon".equalsIgnoreCase(gcMode)) {
                   addCommentOnce(data, RecommendationLabels.HEAP_TUNING_GENCON);
                 } else if ("balanced".equalsIgnoreCase(gcMode)) {
                   addCommentOnce(data, RecommendationLabels.HEAP_TUNING_BALANCED);
                 }
               }
               
               protected boolean is64bitSystem(AggregateData data) {
                 boolean is64 = false;
                 StructuredData systemInformation = data
                   .getStructuredData("VGCLabels.system.attributes");
                 if (systemInformation != null) {
                   String system = 
                     (String)systemInformation.getContents().get("architecture");
                   for (String arch : sixtyFourArch) {
                     if (arch.equalsIgnoreCase(system)) {
                       is64 = true;
                     }
                   }
                 }
                 return is64;
               }
             }


